package com.huilian.iotbox.data.utils;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.spec.KeySpec;
import java.util.Arrays;

/**
 * Created by minechen on 2019/7/29 12:09
 */
public class IotBoxUtil {

    /**
     * 字节数组转16进制
     *
     * @param bytes
     * @return
     */
    public static String byte2Hex(byte[] bytes) {
        StringBuffer stringBuffer = new StringBuffer();
        String temp = null;
        for (int i = 0; i < bytes.length; i++) {
            temp = Integer.toHexString(bytes[i] & 0xFF);
            if (temp.length() == 1) {
                //得到一位的进行补0操作
                stringBuffer.append("0");
            }
            stringBuffer.append(temp);
        }
        return stringBuffer.toString();
    }

    /**
     * hex字符串转byte数组
     *
     * @param inHex 待转换的Hex字符串
     * @return 转换后的byte数组结果
     */
    public static byte[] hex2Bytes(String inHex) {
        int hexlen = inHex.length();
        byte[] result;
        if (hexlen % 2 == 1) {
            //奇数
            hexlen++;
            result = new byte[(hexlen / 2)];
            inHex = "0" + inHex;
        } else {
            //偶数
            result = new byte[(hexlen / 2)];
        }
        int j = 0;
        for (int i = 0; i < hexlen; i += 2) {
            result[j] = hexToByte(inHex.substring(i, i + 2));
            j++;
        }
        return result;
    }

    /**
     * 生成校验码，1个字节
     *
     * @param para
     * @return
     */
    public static String checkcode_0007(String para) {
        int len = para.length() / 2;
        String[] dateArr = new String[len];
        for (int i = 0; i < len; i++) {
            dateArr[i] = para.substring(i * 2, (i + 1) * 2);
        }
        String code = "";
        for (int i = 0; i < dateArr.length - 1; i++) {
            if (i == 0) {
                code = xor(dateArr[i], dateArr[i + 1]);
            } else {
                code = xor(code, dateArr[i + 1]);
            }
        }
        // 有时候会生成一位的，一位的时候要在前面补位
        if (code.length() == 1) {
            code = "0" + code;
        }
        return code.toUpperCase();
    }

    /**
     * 异或运算
     *
     * @param strHex_X
     * @param strHex_Y
     * @return
     */
    private static String xor(String strHex_X, String strHex_Y) {
        //将x、y转成二进制形式
        String anotherBinary = Integer.toBinaryString(Integer.valueOf(strHex_X, 16));
        String thisBinary = Integer.toBinaryString(Integer.valueOf(strHex_Y, 16));
        StringBuilder result = new StringBuilder();
        //判断是否为8位二进制，否则左补零
        if (anotherBinary.length() != 8) {
            for (int i = anotherBinary.length(); i < 8; i++) {
                anotherBinary = "0" + anotherBinary;
            }
        }
        if (thisBinary.length() != 8) {
            for (int i = thisBinary.length(); i < 8; i++) {
                thisBinary = "0" + thisBinary;
            }
        }
        //异或运算
        for (int i = 0; i < anotherBinary.length(); i++) {
            //如果相同位置数相同，则补0，否则补1
            if (thisBinary.charAt(i) == anotherBinary.charAt(i)) {
                result.append("0");
            } else {
                result.append("1");
            }
        }
        return Integer.toHexString(Integer.parseInt(result.toString(), 2));
    }

    /**
     * 十六进制字符串高低位转换
     * 低位(数值大)在前，高位在后
     *
     * @return
     */
    public static String reverseHex(String hex) {
        char[] charArray = hex.toCharArray();
        int length = charArray.length;
        int times = length / 2;
        for (int c1i = 0; c1i < times; c1i += 2) {
            int c2i = c1i + 1;
            char c1 = charArray[c1i];
            char c2 = charArray[c2i];
            int c3i = length - c1i - 2;
            int c4i = length - c1i - 1;
            charArray[c1i] = charArray[c3i];
            charArray[c2i] = charArray[c4i];
            charArray[c3i] = c1;
            charArray[c4i] = c2;
        }
        String s = new String(charArray);
        if (s.length() == 2) {
            return s + "00";
        }
        return s;
    }

    /***
     * 补码 00
     * @param num 数量
     * @return
     */
    public static String complement(int num) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < num; i++) {
            sb.append("00");
        }
        return sb.toString();
    }

    /**
     * 16进制转10进制
     *
     * @param hex 一串
     * @return
     */
    public static int[] hex2Int(String hex) {
        System.out.println("hex长度: " + hex.length());
        int[] res = new int[hex.length() / 2];
        for (int i = 0; i < hex.length() / 2; i++) {
            String str = hex.substring(i * 2, 2 * i + 2);
            System.out.print(str + ",");
            res[i] = Integer.parseInt(str, 16);
        }
        return res;
    }

    /**
     * 批量10进制转16进制
     *
     * @param hex 一串
     * @return
     */
    public static String hex2Str(int[] hex) {
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < hex.length; i++) {
            stringBuffer.append(singleInt2Hex(hex[i]));
        }
        return stringBuffer.toString();
    }

    /**
     * 16进制转10进制
     * 高位在前，低位在后
     *
     * @param hex
     * @return
     */
    public static int singleHex2Int(String hex) {
        // 兼容负数
        BigInteger ten = new BigInteger(hex, 16);
        return ten.intValue();
    }

    /**
     * 10进制转16进制，0-255=1字节，大于255=2字节起步
     * 高位在前，低位在后
     *
     * @param in
     * @return
     */
    public static String singleInt2Hex(int in) {
        StringBuffer sb = new StringBuffer();
        String str = Integer.toHexString(in);
        if (str.length() % 2 == 1) {
            sb.append("0");
        }
        sb.append(str);
        return sb.toString();
    }


    /**
     * 10进制转16进制，2字节
     * 高位在前，低位在后
     *
     * @param in    整数
     * @param bytes 需转换几个字节
     * @return
     */
    public static String singleInt2Hex_2(int in, int bytes) {
        StringBuilder sb = new StringBuilder();
        String str = Integer.toHexString(in);
        for (int i = bytes * 2 - str.length(); i > 0; i--) {
            sb.append("0");
        }
        sb.append(str);
        return sb.toString();
    }

    /**
     * Hex字符串转byte
     *
     * @param inHex 待转换的Hex字符串
     * @return 转换后的byte
     */
    public static byte hexToByte(String inHex) {
        return (byte) Integer.parseInt(inHex, 16);
    }

    /**
     * YYMMddHHmmss转16进制
     *
     * @param date
     * @return
     */
    public static StringBuffer date2Hex(String date) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < date.length() / 2; i++) {
            String str = date.substring(i * 2, 2 * i + 2);
            String hex = Integer.toHexString(Integer.parseInt(str));
            if (hex.length() == 1) {
                //补0
                sb.append("0");
            }
            sb.append(hex);
        }
        return sb;
    }

    /**
     * 16进制转HH:mm:ss
     *
     * @param hex
     * @return
     */
    public static String hex2Date(String hex) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < hex.length(); i += 2) {
            String str = hex.substring(i, Math.min(i + 2, hex.length()));
            int decimal = Integer.parseInt(str, 16);
            sb.append(String.format("%02d", decimal)); // 补零
            if (i < 4) {
                sb.append(":"); // 在小时和分钟之间，分钟和秒之间添加冒号
            }
        }
        return sb.toString();
    }

    /**
     * 备用异或计算，生产环境禁用
     *
     * @param content
     * @return
     */
    public static String yiHuo(String content) {
        int a = 0;
        for (int i = 0; i < content.length() / 2; i++) {
            a = a ^ Integer.parseInt(content.substring(i * 2, (i * 2) + 2), 16);
        }
        String result = Integer.toHexString(a);
        if (result.length() == 1) {
            return "0" + result;
        } else {
            return result;
        }
    }

    public static void main(String[] args) throws Exception {
//        System.out.println(IotBoxUtil.convertHexToString("3839383630344431323232324430323535323638"));
//        System.out.println(IotBoxUtil.hexStr2Str("5847496E0100".substring(0,8)));
//        System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMddHHmmss")));
//        System.out.println(IotBoxUtil.date2Hex(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMddHHmmss"))));
//        System.out.println(IotBoxUtil.yiHuo("0502010115"));
        System.out.println(IotBoxUtil.checkcode_0007("0502017c176D"));
        /**
         * aa 1301060A0A0A23091e0901000101001E010009 34 dd
         * aa 1301060A0A0A1709270901000101001E010009 39 dd
         * aa 1301060A0A0A1009230901000101001E010009 3A dd
         * aa 1301060A0A0A0f09130901000101001E010009 15 dd
         */
//        System.out.println(IotBoxUtil.singleInt2Hex_2(2, 2));
//        String id = "12b6a66";
//        String s = IotBoxUtil.convertStringToHex(id);
//        System.out.println(s);
//        System.out.println(IotBoxUtil.convertHexToString(s));


//        System.out.println(IotBoxUtil.singleHex2Int(IotBoxUtil.reverseHex("00960000")));

//        String hex = "AA270110687474703A2F2F6D2E6C6579616F79616F2E636F6D2F6C79792F742F323932323130383420DD";
//        System.out.println(IotBoxUtil.hexStr2Str(hex));
//
//        String hex2 = "https://client.iotbox.cn/c?d=600001";
//        System.out.println(IotBoxUtil.str2HexStr(hex2));

        /**
         * http://m.leyaoyao.com/lyy/t/29221084
         * https://client.iotbox.cn/c?d=600001
         */

        /**
         * AA270110687474703A2F2F6D2E6C6579616F79616F2E636F6D2F6C79792F742F323932323130383420DD
         * 68747470733A2F2F6D2E6C6579616F79616F2E636F6D2F637573746F6D65722F6D6573736167652F742F3239323231303834
         *
         * 687474703A2F2F6D2E6C6579616F79616F2E636F6D2F6C79792F742F3239323231303834
         * 687474703A2F2F6D2E6C6579616F79616F2E636F6D2F6C79792F742F3239323231303834
         */


//        System.out.println(IotBoxUtil.convertStringToHex("123456"));

        // 68747470733a2f2f762e646f7579696e2e636f6d2f6877795158586e2f
        // 84403aff6e4f599ee3fdf879188ef
        // 84403aff6e4f599ee3fdf8358368f

//        System.out.println(IotBoxUtil.hexStr2Str("68747470733a2f2f762e646f7579696e2e636f6d2f687779374e75722f"));
//
//        String hex = "68747470733a2f2f762e646f7579696e2e636f6d2f687779374e75722f";
//        String hexStr = "";
//        String str = "0123456789ABCDEF"; //16进制能用到的所有字符 0-15
//        for(int i=0;i<hex.length();i++){
//            String s = hex.substring(i, i+1);
//            if(s.equals("a")||s.equals("b")||s.equals("c")||s.equals("d")||s.equals("e")||s.equals("f")){
//                s=s.toUpperCase().substring(0, 1);
//            }
//            hexStr += s;
//        }
//        char[] hexs = hexStr.toCharArray();//toCharArray() 方法将字符串转换为字符数组。
//        int length = (hexStr.length() / 2);//1个byte数值 -> 两个16进制字符
//        byte[] bytes = new byte[length];
//        int n;
//        for (int i = 0; i < bytes.length; i++) {
//            int position = i * 2;//两个16进制字符 -> 1个byte数值
//            n = str.indexOf(hexs[position]) * 16;
//            n += str.indexOf(hexs[position + 1]);
//            // 保持二进制补码的一致性 因为byte类型字符是8bit的  而int为32bit 会自动补齐高位1  所以与上0xFF之后可以保持高位一致性
//            //当byte要转化为int的时候，高的24位必然会补1，这样，其二进制补码其实已经不一致了，&0xff可以将高的24位置为0，低8位保持原样，这样做的目的就是为了保证二进制数据的一致性。
//            bytes[i] = (byte) (n & 0xff);
//        }
//        String name = "";
//        try {
//            name = new String(bytes,"UTF-8");
//        } catch (UnsupportedEncodingException e) {
//            e.printStackTrace();
//        }
//        System.out.println(name);
    }

    /**
     * 字符串转换成为16进制字符串(无需Unicode编码)
     *
     * @param str
     * @return
     */
    public static String str2HexStr(String str) {
        char[] chars = "0123456789ABCDEF".toCharArray();
        StringBuilder sb = new StringBuilder("");
        byte[] bs = str.getBytes();
        int bit;
        for (int i = 0; i < bs.length; i++) {
            bit = (bs[i] & 0x0f0) >> 4;
            sb.append(chars[bit]);
            bit = bs[i] & 0x0f;
            sb.append(chars[bit]);
            // sb.append(' ');
        }
        return sb.toString().trim();
    }

    /**
     * 16进制字符串直接转换成为字符串(无需Unicode解码)
     *
     * @param hexStr
     * @return
     */
    public static String hexStr2Str(String hexStr) {
        String str = "0123456789ABCDEF";
        char[] hexs = hexStr.toCharArray();
        byte[] bytes = new byte[hexStr.length() / 2];
        int n;
        for (int i = 0; i < bytes.length; i++) {
            n = str.indexOf(hexs[2 * i]) * 16;
            n += str.indexOf(hexs[2 * i + 1]);
            bytes[i] = (byte) (n & 0xff);
        }
        return new String(bytes);
    }

    /**
     * 将字符串转为字节数组
     *
     * @param hex
     * @return
     */
    public static byte[] hexStr2Byte(String hex) {
        ByteBuffer bf = ByteBuffer.allocate(hex.length() / 2);
        for (int i = 0; i < hex.length(); i++) {
            String hexStr = hex.charAt(i) + "";
            i++;
            hexStr += hex.charAt(i);
            byte b = (byte) Integer.parseInt(hexStr, 16);
            bf.put(b);
        }
        return bf.array();
    }


    /**
     * int转2个字节的16进制 例：1 --> 0001
     *
     * @param length
     * @return
     */
    public static String int2ByteHex(int length) {
        StringBuffer sb = new StringBuffer();
        String str = Integer.toHexString(length);
        sb.append(appendZero(str));
        if (sb.length() > 4) {
            throw new IllegalStateException(length + "16进制超过2个字节");
        }
        return sb.toString();
    }


    private static String appendZero(String hex) {
        if (hex != null && hex.length() < 4) {
            hex = "0" + hex;
            if (hex.length() < 4) {
                return appendZero(hex);
            }
            return hex;
        } else {
            return hex;
        }
    }


    /**
     * 10进制字符串转换为16进制字符串
     * 每个字符转换为其对应的ASCII码的十六进制表示，并将这些十六进制数连接成一个新的字符串
     *
     * @param str
     *
     * @return
     */
    public static String convertStringToHex(String str) {

        char[] chars = str.toCharArray();
        StringBuffer hex = new StringBuffer();
        for (int i = 0; i < chars.length; i++) {
            hex.append(Integer.toHexString(chars[i]));
        }
        return hex.toString();
    }

    /**
     * 16进制字符串转换为10进制字符串
     *
     * @param hex
     * @return
     */
    public static String convertHexToString(String hex) {
        StringBuilder sb = new StringBuilder();
        //49204c6f7665204a617661 split into two characters 49, 20, 4c...
        for (int i = 0; i < hex.length() - 1; i += 2) {

            //grab the hex in pairs
            String output = hex.substring(i, (i + 2));
            //convert hex to decimal
            int decimal = Integer.parseInt(output, 16);
            //convert the decimal to character
            sb.append((char) decimal);
        }
        return sb.toString();
    }

    /**
     * 16进制，高位在前 转 低位在前
     *
     * @param hex
     * @return
     */
    public static String hexHighToLow(String hex) {
        char[] charArray = hex.toCharArray();
        int length = charArray.length;
        int times = length / 2;
        for (int c1i = 0; c1i < times; c1i += 2) {
            int c2i = c1i + 1;
            char c1 = charArray[c1i];
            char c2 = charArray[c2i];
            int c3i = length - c1i - 2;
            int c4i = length - c1i - 1;
            charArray[c1i] = charArray[c3i];
            charArray[c2i] = charArray[c4i];
            charArray[c3i] = c1;
            charArray[c4i] = c2;
        }
        return new String(charArray);
    }


    /**
     * 10进制转16进制  String类型整个转换，然后是8个字节
     *
     * @param hex
     * @return
     */
    public static String singleString2Hex(String hex) {
        String hexString = String.format("%016X", Long.parseLong(hex));
        return hexString;
    }

    /**
     * 共享街机 命令 + LEN + DATA的累加和
     * (低字节在前)
     * @param hex
     * @return
     */
    public static Integer checkcodeSUM(String hex) {
        String hexdata = hex;
        hexdata = hexdata.replaceAll(" ", "");
        int total = 0;
        int len = hexdata.length();
        if (len % 2 != 0) {
            System.out.println("000");
            return 00;
        }
        int num = 0;
        while (num < len) {
            String s = hexdata.substring(num, num + 2);
            total += Integer.parseInt(s, 16);
            num = num + 2;
        }
        return total;
    }


    public static byte[] DESEncrypt(byte[] data, byte[] key) {
        try {
            // 使用相同的密钥作为IV
            byte[] iv = Arrays.copyOf(key, 4);

            // 创建DES密钥规范
            KeySpec keySpec = new DESKeySpec(key);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secretKey = keyFactory.generateSecret(keySpec);

            // 创建初始化向量（IV）参数规范
            IvParameterSpec ivSpec = new IvParameterSpec(iv);

            // 创建DES加密器
            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);

            // 执行加密
            byte[] encryptedData = cipher.doFinal(data);

            return encryptedData;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static byte[] DESDecrypt(byte[] encryptedData, byte[] key) {
        try {
            // 使用相同的密钥作为IV
            byte[] iv = Arrays.copyOf(key, 8);

            // 创建DES密钥规范
            KeySpec keySpec = new DESKeySpec(key);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secretKey = keyFactory.generateSecret(keySpec);

            // 创建初始化向量（IV）参数规范
            IvParameterSpec ivSpec = new IvParameterSpec(iv);

            // 创建DES解密器
            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);

            // 执行解密
            byte[] decryptedData = cipher.doFinal(encryptedData);

            return decryptedData;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Integer convertToTwoDigit(int layer, int column) {
        int layerValue = layer * 10;
        int twoDigitValue = layerValue - 10;
        return twoDigitValue +column;
    }

}
